import com.yoke.util.FileUtil;

import javax.tools.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by jiangzeyin on 2017/7/13.
 */
public class TEst2 {
    private static Map<String, JavaFileObject> fileObjects = new ConcurrentHashMap<>();

    public static void main(String[] args) throws IOException {

        //D:\ide\tools\good_tools\src\test\java
        //D:\yokead_boot\java\images
        File file = new File("D:\\yokead_boot\\java\\images");
        File[] files = file.listFiles();
        for (File item : files) {
            if (!item.isFile())
                continue;
            String cls = item.getName().replace(".java", "");
            System.out.println(cls);
            String code = FileUtil.readToString(item);
            JavaFileObject javaFileObject = new MyJavaFileObject(cls, code);
            compiler(javaFileObject);
        }


        ClassLoader classloader = new MyClassLoader();

        Class<?> clazz = null;
        try {
            clazz = classloader.loadClass("com.yoke.publish.PublishImages");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Method method = null;
        try {
            method = clazz.getDeclaredMethod("init");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            method.invoke(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private static void compiler(JavaFileObject javaFileObject) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        //DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<JavaFileObject>() {
//            @Override
//            public void report(Diagnostic diagnostic) {
//                super.report(diagnostic);
//
//
//
//            }
//        };

        DiagnosticListener DiagnosticListener = new DiagnosticListener<JavaFileObject>() {
            @Override
            public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
                if (diagnostic.getKind() == Diagnostic.Kind.ERROR)
                    System.err.println(diagnostic.getLineNumber() + ":"
                            + diagnostic.getMessage(Locale.CHINESE));
            }
        };
        JavaFileManager javaFileManager = new MyJavaFileManager(compiler.getStandardFileManager(DiagnosticListener, null, null));

        List<String> options = new ArrayList<>();
        options.add("-target");
        options.add("1.8");
        options.add("-source");
        options.add("1.8");
        options.add(null);
        File file = new File("D:\\ide\\lib");
        File[] files = file.listFiles();
        StringBuilder stringBuffer = new StringBuilder();
        for (File item : files) {
            if (stringBuffer.length() != 0)
                stringBuffer.append(";");
            stringBuffer.append(item.getPath());
        }
        //options.add("-Xlint:unchecked");
        options.add("-classpath");
        options.add(stringBuffer.toString());
        options.add("-sourcepath");
        options.add(stringBuffer.toString());

        System.out.println(stringBuffer);
        Iterable<String> options_ = Arrays.asList("-encoding", "UTF-8", "-classpath",stringBuffer.toString());

        Boolean result = compiler.getTask(null, javaFileManager, DiagnosticListener, options_, null, Collections.singletonList(javaFileObject)).call();
        System.out.println(result + " 编译结果");
        System.out.println(options);

    }

    public static class MyClassLoader extends ClassLoader {

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            JavaFileObject fileObject = fileObjects.get(name);
            if (fileObject != null) {
                byte[] bytes = ((MyJavaFileObject) fileObject).getCompiledBytes();
                return defineClass(name, bytes, 0, bytes.length);
            }
            try {
                return ClassLoader.getSystemClassLoader().loadClass(name);
            } catch (Exception e) {
                return super.findClass(name);
            }
        }
    }

    public static class MyJavaFileObject extends SimpleJavaFileObject {
        private String source;
        private ByteArrayOutputStream outPutStream;


        public MyJavaFileObject(String name, String source) {
            super(URI.create("String:///" + name + Kind.SOURCE.extension), Kind.SOURCE);
            this.source = source;
        }

        public MyJavaFileObject(String name, Kind kind) {
            super(URI.create("String:///" + name + kind.extension), kind);
            source = null;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            if (source == null) {
                throw new IllegalArgumentException("source == null");
            }
            return source;
        }

        @Override
        public OutputStream openOutputStream() throws IOException {
            outPutStream = new ByteArrayOutputStream();
            return outPutStream;
        }

        public byte[] getCompiledBytes() {
            return outPutStream.toByteArray();
        }
    }

    public static class MyJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
        protected MyJavaFileManager(JavaFileManager fileManager) {
            super(fileManager);
        }

        @Override
        public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
            JavaFileObject javaFileObject = fileObjects.get(className);
            if (javaFileObject == null) {
                super.getJavaFileForInput(location, className, kind);
            }
            return javaFileObject;
        }

        @Override
        public JavaFileObject getJavaFileForOutput(Location location, String qualifiedClassName, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
            JavaFileObject javaFileObject = new MyJavaFileObject(qualifiedClassName, kind);
            fileObjects.put(qualifiedClassName, javaFileObject);
            return javaFileObject;
        }
    }
}
